﻿using System;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using Microsoft.AspNetCore.Cryptography.KeyDerivation;

namespace Chengqbd.Core.Common
{
	public class PasswordHelper
	{
        /// <summary>
        /// 密码加密
        /// </summary>
        /// <param name="password"></param>
        /// <returns></returns>
		public static string HashPassword(string password)
		{
			bool flag = password == null;
			if (flag)
			{
				throw new ArgumentNullException("password");
			}
			int num = 16;
			KeyDerivationPrf keyDerivationPrf = KeyDerivationPrf.HMACSHA256;
			int iterCount = _iterCount;
			int num2 = 32;
			byte[] array = new byte[num];
            _rng.GetBytes(array);
			byte[] array2 = KeyDerivation.Pbkdf2(password, array, keyDerivationPrf, iterCount, num2);
			byte[] array3 = new byte[13 + array.Length + array2.Length];
			array3[0] = 1;
            WriteNetworkByteOrder(array3, 1, (uint)keyDerivationPrf);
            WriteNetworkByteOrder(array3, 5, (uint)iterCount);
            WriteNetworkByteOrder(array3, 9, (uint)num);
			Buffer.BlockCopy(array, 0, array3, 13, array.Length);
			Buffer.BlockCopy(array2, 0, array3, 13 + num, array2.Length);
			return Convert.ToBase64String(array3);
		}
        /// <summary>
        /// 检索密码
        /// </summary>
        /// <param name="hashedPassword"></param>
        /// <param name="providedPassword"></param>
        /// <returns></returns>
		public static bool VerifyHashedPassword(string hashedPassword, string providedPassword)
		{
			bool flag = hashedPassword == null;
			if (flag)
			{
				throw new ArgumentNullException("hashedPassword");
			}
			bool flag2 = providedPassword == null;
			if (flag2)
			{
				throw new ArgumentNullException("providedPassword");
			}
			byte[] array = Convert.FromBase64String(hashedPassword);
			bool flag3 = array.Length == 0;
			return !flag3 && PasswordHelper.VerifyHashedPasswordV3(array, providedPassword, PasswordHelper._iterCount);
		}
        
		private static uint ReadNetworkByteOrder(byte[] buffer, int offset)
		{
			return (uint)((int)buffer[offset] << 24 | (int)buffer[offset + 1] << 16 | (int)buffer[offset + 2] << 8 | (int)buffer[offset + 3]);
		}
        
		private static bool VerifyHashedPasswordV3(byte[] hashedPassword, string password, int iterCount)
		{
			bool result;
			try
			{
				KeyDerivationPrf keyDerivationPrf =(KeyDerivationPrf) PasswordHelper.ReadNetworkByteOrder(hashedPassword, 1);
				int num = (int)PasswordHelper.ReadNetworkByteOrder(hashedPassword, 9);
				bool flag = num < 16;
				if (flag)
				{
					result = false;
				}
				else
				{
					byte[] array = new byte[num];
					Buffer.BlockCopy(hashedPassword, 13, array, 0, array.Length);
					int num2 = hashedPassword.Length - 13 - array.Length;
					bool flag2 = num2 < 16;
					if (flag2)
					{
						result = false;
					}
					else
					{
						byte[] array2 = new byte[num2];
						Buffer.BlockCopy(hashedPassword, 13 + array.Length, array2, 0, array2.Length);
						byte[] a = KeyDerivation.Pbkdf2(password, array, keyDerivationPrf, PasswordHelper._iterCount, num2);
						result = PasswordHelper.ByteArraysEqual(a, array2);
					}
				}
			}
			catch
			{
				result = false;
			}
			return result;
		}
        
		private static void WriteNetworkByteOrder(byte[] buffer, int offset, uint value)
		{
			buffer[offset] = (byte)(value >> 24);
			buffer[offset + 1] = (byte)(value >> 16);
			buffer[offset + 2] = (byte)(value >> 8);
			buffer[offset + 3] = (byte)value;
		}
        
		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		private static bool ByteArraysEqual(byte[] a, byte[] b)
		{
			bool flag = a == null && b == null;
			bool result;
			if (flag)
			{
				result = true;
			}
			else
			{
				bool flag2 = a == null || b == null || a.Length != b.Length;
				if (flag2)
				{
					result = false;
				}
				else
				{
					bool flag3 = true;
					for (int i = 0; i < a.Length; i++)
					{
						flag3 &= (a[i] == b[i]);
					}
					result = flag3;
				}
			}
			return result;
		}
        
		private static readonly int _iterCount = 10000;
        
		private static readonly RandomNumberGenerator _rng = RandomNumberGenerator.Create();
	}
}
